import json

import  serial
import  time
import threading
import  os
import requests
class TTerminal645:
    def __init__(self):
        self.config ={
            "comPort":"COM13",
            "baudrate":1200,
            "dbKey":"znv2",
            "apiUrl":"http://127.0.0.1:2200",
            "queryUrl":"http://127.0.0.1:2200/db/ms/query",
            "savePath":"E:/project/zndatas/pt645",
            "postUrl":"http://127.0.0.1:2200/zn/svr/postData"
        }
        self.devs ={}
        self.dps={}
        self.ser = None

        self.loopTime = 60*10
        self.lastReadTime = 0
    def start(self):
        try:
            self.loadDataFromSvr()
            self.saveDps()
            while 1>0:
                nowTm = time.time()
                diffTm = nowTm - self.lastReadTime
                if diffTm > self.loopTime:
                    self.lastReadTime = nowTm
                    strTime = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(nowTm))
                    print(strTime , 'start read 645 datapoints')
                    self.readDps()
                    self.lastReadTime = nowTm
                else:
                    time.sleep(1)
        except Exception as er:
            print(er)
    def loadDataFromSvr(self):
        try:
            ps={
                "dbKey_":self.config["dbKey"],
                "dbPath_":"zn2024/terminal645/get645Objs.txt"
            }
            url = self.config['queryUrl']
            resp = requests.post( url , data=ps)
            datas = json.loads(resp.content)
            for dev in datas["result"][0]:
                dev['dps'] ={}
                self.devs[dev["devCode"]] = dev
            for dp in datas["result"][1]:
                dpCode = dp['dpCode']
                dp['value'] =0
                dp['changed'] = 0
                devCode = dp['devCode']
                dev = self.devs[devCode]
                dev['dps'][dpCode] = dp

                #dp['dev'] = dev
                self.dps[dpCode] = dp
                cmdBytes=[]
                addrBytes = bytes(reversed( bytes.fromhex(dp['devCode'])))
                cmdBytes.append(0x68)
                for i in range(len(addrBytes)):
                    cmdBytes.append(addrBytes[i])
                cmdBytes.append(0x68)
                cmdBytes.append(0x11)
                cmdBytes.append(0x4)
                cmdBytes.append(0x33+dp['a3'])
                cmdBytes.append(0x33+dp['a2'])
                cmdBytes.append(0x33+dp['a1'])
                cmdBytes.append(0x33+dp['a0'])
                cs = 0
                for i in range(len(cmdBytes)):
                    cs = cs + cmdBytes[i]
                    cs = cs % 256
                cmdBytes.append(cs)
                cmdBytes.append(0x16)
                dp['cmdBytes'] = cmdBytes
            print('load dev/datapoints.')
        except Exception as er:
            print(er)
    def close(self):
        try:
            if self.ser!=None:
                self.ser.close()
                self.ser = None
        except Exception as er:
            print(er)
    def readDps(self):
        try:
            comPort = self.config['comPort']
            baudrate = self.config['baudrate']
            ser = serial.Serial(comPort, baudrate , parity=serial.PARITY_EVEN, timeout=2)
            self.ser = ser
            #self.loadDataFromSvr()
            for dp in self.dps.values():
                if self.ser!=None and not self.ser.closed:
                    self.readDatapoint(dp)
                #print('inpurt datapoint.', dp)
            self.close()
            self.saveDps()
            self.postDps()
        except Exception as er:
            print(er)
    def readDatapoint(self, dp ):
        try:
            if self.ser!=None and not self.ser.closed:
                sendBytes = dp["cmdBytes"]
                self.ser.write(sendBytes)
                self.ser.flush()
                time.sleep(0.03)
                flag68H = self.getFirst68H()
                if flag68H :
                    bodySize = self.getBodySize()
                    if bodySize>0:
                        su , body = self.getBody(bodySize)
                        if su:
                            #print('success')
                            dp['valueBody'] = body
                            decodeFlag = self.decode(dp,body)
                            #if decodeFlag :
                            #    print('success' , dp)
                        else:
                            print('fail.', dp)

        except Exception as er:
            print(er)
    def getFirst68H(self):
        res = False
        try:
            while not self.ser.closed:
                try:
                    r = self.ser.read(1)
                    if len(r)>0:
                        if r[0]==0x68:
                            res = True
                            break
                    else:
                        print('rec data timeout. get-68H')
                        time.sleep(1)
                        res = False
                        break
                except Exception as eer:
                    print(eer)
                    res = False
                    break
        except Exception as er:
            print(er)
        return  res
    def getBodySize(self):
        res = -1
        try:
            if not self.ser.closed:
                try:
                    r = self.ser.read(9)
                    if len(r)==9 and r[-3]==0x68:
                        res = r[-1]
                    else:
                        print('rec data timeout.-- bodysize', len(r))
                        res = -1
                except Exception as eer:
                    print(eer)
                    res = False
        except Exception as er:
            print(er)
        return  res
    def getBody(self, bodySize):
        resSuccess = False
        resBody= []
        try:
            if not self.ser.closed:
                try:
                    recSize = bodySize+2
                    r = self.ser.read(recSize)
                    if len(r)==recSize and r[-1]==0x16:
                        bodyBytes= list( reversed( r[4:-2]))
                        resBody = [ ((hex(x-0x33)).replace('0x','')).zfill(2) for x in bodyBytes]
                        resSuccess = True
                    else:
                        print('rec data timeout.-- body ')
                        res = -1
                except Exception as eer:
                    print(eer)
                    resSuccess = False
                    resBody =[]
        except Exception as er:
            print(er)
        return  (resSuccess , resBody)
    def decode(self , dp, recBody):
        successFlag = False
        try:
            dp['changed'] = 0
            a0 = dp['a0']
            a1 = dp['a1']
            a2 = dp['a2']
            a3 = dp['a3']
            valStr = "0"
            if a0 == 0 :
                valStr = "".join(recBody[:-1])+"."+"".join(recBody[-1:])
                dp['valueStr'] = valStr
                dp['value'] = float(valStr)
                successFlag = True
            elif a0 == 1 :
                valTime = "".join(recBody[:5])
                valStr = recBody[5]+"."+"".join(recBody[6:])
                dp['valueStr'] = valStr
                dp['valueTime'] = valTime
                dp['value'] = float(valStr)
                successFlag = True
            elif a0 == 2:
                if a1 == 1 :
                    st = "".join(recBody)
                    valStr = st[:-1]+"."+st[-1]
                    successFlag = True
                elif a1 == 2 :
                    st = "".join(recBody)
                    valStr = st[:-3]+"."+st[-3:]
                    successFlag = True
                elif a1 == 3 or a1 == 4 or a1 == 5 :
                    st = "".join(recBody)
                    valStr = st[:2]+"."+st[2:]
                    successFlag = True
                elif a1 == 6 :
                    st = "".join(recBody)
                    valStr = st[0]+"."+st[1:]
                    successFlag = True
                dp['valueStr'] = valStr
                dp['value'] = float(valStr)
            if successFlag :
                value = dp['value']
                changed = 0
                if 'oldValue' in dp.keys():
                    oldValue = dp['oldValue']
                    if value!=0 and oldValue == 0 :
                        changed = 1
                    elif oldValue!=0:
                        diff = abs(value - oldValue)*100.0/abs(oldValue)
                        if diff>5:
                            changed = 1
                else:
                    dp['oldValue'] = value
                    changed = 1
                dp['changed'] = changed
        except Exception as er :
            successFlag = False
            print(er)
        return  successFlag
    def postDps(self):
        try:
            postData ={}
            for dpK , dp in self.dps.items():
                if dp['changed']>0:
                    postData[dp['dpCode']] = dp['value']
            url = self.config['postUrl']
            resp = requests.post(url , postData)
            print('post datapoint.',resp)
        except Exception as er:
            print(er)
    def readDatapoint_(self, dp):
        try:
            if self.ser!=None and not self.ser.closed:
                sendBytes = dp["cmdBytes"]
                self.ser.write(sendBytes)
                self.ser.flush()
                time.sleep(0.03)
                flag = True
                recBytes =[]
                while not self.ser.closed:
                    try:
                        r = self.ser.read(1)
                        if len(r)>0:
                            count = 0
                            rb = r[0]
                            recBytes.append(rb)
                            if rb == 0x16:
                                flag = self.checkDp(dp , recBytes)
                                if flag:
                                    break
                        else:
                            print('rec data timeout.')
                            flag = False
                            break
                    except Exception as eer:
                        print(eer)
                if flag :
                    self.decodeDp(dp , recBytes)
        except Exception as er:
            print(er)
    def checkDp(self , dp ,recBytes):
        res = False
        try:
            res = len(recBytes)>18
            # if res :
            #     cs =0
            #     count = len(recBytes) - 2 - 4
            #     dpCs = recBytes[count+4]
            #     for i in range(count):
            #         v = cs + recBytes[i+4]
            #         a = v % 256
            #         print('cs:', cs, "+", recBytes[i] , "=" ,v , ">" , a)
            #         cs = a
            #
            #     res = dpCs == cs
            # else:
            #     print('decode error:' , dp)
        except Exception as er:
            print(er)
        return  res
    def decodeDp(self , dp ,recBytes):
        try:
            dataLen = dp['dataLen']
            dataBytes = reversed( recBytes[-2-dataLen : -2])
            dataBytes = [(hex(x-0x33)).replace('0x','').zfill(2) for x in dataBytes]

            dataStr = "".join(dataBytes)
            intLen = dp['intLen']
            decLen = dp['decLen']
            timeLen = dp['timeLen']
            rate = dp['rate']
            pos=0
            dataInt = dataStr[pos:pos+intLen]
            pos = pos + intLen
            dataDec = dataStr[pos:pos+decLen]
            pos = pos + decLen
            dataTime = '' if timeLen==0 else dataStr[pos:]
            dp['valueStr'] = dataInt+"."+dataDec
            nv = float(dp['valueStr'])
            dp['value'] = nv if rate==0 else  rate * nv
            dp['valueTime'] = dataTime
            dp['dataBytes'] = dataBytes
            print(dp)
        except Exception as er:
            print(er)
    def saveDps(self):
        try:
            tm = time.localtime( time.time())
            strDay = time.strftime('%Y%m%d', tm)
            strTm = time.strftime("%H%M%S", tm)
            dir = "/".join([self.config['savePath'] , strDay])
            if not os.path.exists(dir):
                os.makedirs(dir)
            fn = dir +"/"+strTm+".json"
            with open(fn , 'w' , encoding='utf8') as f:
                data = json.dumps(self.devs , ensure_ascii=False)
                f.write(data)

            smallData =[]
            for dev in self.devs.values():
                devInfo ={
                    'devCode': dev['devCode'],
                    "dps": {}
                }
                for dp in dev['dps'].values():
                    devInfo['dps'][dp['dpCode']] = dp['value']
                smallData.append(devInfo)
            smallDataJson = json.dumps(smallData)
            fn = dir +"/small_"+strTm+".json"
            with open(fn , 'w' , encoding='utf8') as f:
                f.write(smallDataJson)
        except Exception as er:
            print(er)


t645 = TTerminal645()
t645.start()